﻿using System;
using System.Text;
using System.Text.RegularExpressions;

namespace Zo.Extensions
{
    /// <summary>
    /// 字符串扩展信息。
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// 验证 IP 的正则表达式。
        /// </summary>
        private static readonly Regex _ipExpression = new Regex(@"(((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)((\:\d{0,5}){0,1}))");

        /// <summary>
        /// 当前字符串是 null 还是 System.String.Empty 字符串。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <returns>是否为空。</returns>
        public static bool IsNullOrEmpty(this string target) => string.IsNullOrEmpty(target);

        /// <summary>
        /// 指示指定的字符串是 null、空还是仅由空白字符组成。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <returns>如果 value 参数为 null 或 System.String.Empty，或者如果 value 仅由空白字符组成，则为 true。</returns>
        public static bool IsNullOrWhiteSpace(this string target) => string.IsNullOrWhiteSpace(target);

        /// <summary>
        /// 判断对象是否为 System.Int32 类型的数字。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <returns>如果 target 参数为 System.Int32 类型的数字，则为 true。</returns>
        public static bool IsNumeric(this string target)
        {
            if (string.IsNullOrWhiteSpace(target)) return false;

            return target.Length > 0 && Regex.IsMatch(target, @"^[-]?[0-9]*[.]?[0-9]*$");
        }

        /// <summary>
        /// 验证手机号。
        /// </summary>
        /// <param name="val"></param>
        /// <returns></returns>
        public static bool IsMobile(this string val)
        {
            if (string.IsNullOrWhiteSpace(val)) return false;

            return val.Length == 11 && val.StartsWith("1");
        }

        /// <summary>
        /// 验证当前字符串是否为 System.DateTime 类型。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <returns>如果 target 参数为 System.DateTime 类型，则为 true。</returns>
        public static bool IsDateTime(this string target)
        {
            if (string.IsNullOrWhiteSpace(target)) return false;
            return target.Length > 0 && Regex.IsMatch(target, @"^((\d{2}(([02468][048])|([13579][26]))[\-\/\s]((((0?[13578])|(1[02]))[\-\/\s]((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][1235679])|([13579][01345789]))[\-\/\s]((((0?[13578])|(1[02]))[\-\/\s]((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]((0?[1-9])|(1[0-9])|(2[0-8]))))))(\s(((0?[0-9])|(2[0-3])|(1[0-9]))\:([0-5]?[0-9])((\s)|(\:([0-5]?[0-9])))))?$");
        }

        /// <summary>
        /// 判断当前字符串是否在指定的范围内。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <param name="minLength">最小长度。</param>
        /// <param name="maxLength">最大长度。</param>
        /// <returns>在指定的范围内，则为 true。</returns>
        public static bool Range(this string target, int minLength, int maxLength) => !string.IsNullOrWhiteSpace(target) && target.Length >= minLength && target.Length <= maxLength;

        /// <summary>
        /// 对进当字符串进行哈希。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <returns>哈希值。</returns>
        public static string Hash(this string target)
        {
            using (var md5 = System.Security.Cryptography.MD5.Create())
            {
                var data = Encoding.Unicode.GetBytes(target);
                var hash = md5.ComputeHash(data);

                return Convert.ToBase64String(hash);
            }
        }

        /// <summary>
        /// 指示 System.Text.RegularExpressions.Regex 构造函数中指定的正则表达式在指定的输入字符串中是否找到了匹配项。
        /// </summary>
        /// <param name="target">当前字符串。</param>
        /// <param name="expressionString">正则表达式。</param>
        /// <returns>验证通过，则为 True。</returns>
        public static bool IsMatch(this string target, string expressionString)
        {
            if (string.IsNullOrWhiteSpace(target)) return false;
            var expression = new Regex(expressionString);
            return expression.IsMatch(target);
        }

        /// <summary>
        /// 获取字符串真实长度。
        /// </summary>
        /// <remarks>1个汉字等于2个字符。</remarks>
        /// <param name="text">当前字符串。</param>
        /// <returns>字符串真实长度。</returns>
        public static int Length(this string text) => Encoding.Default.GetBytes(text).Length;

        /// <summary>
        /// 限制字符串长度，如果字符串的字符数超过 length，则忽略多出来的字符。
        /// </summary>
        /// <param name="text">原字符串。</param>
        /// <param name="length">限制字符串的字符数量。</param>
        /// <param name="tag">省略标记。</param>
        /// <returns>如果字符串的字符数没有超过 length 则直接返回原字符串，否则将超出的字符删除并加上省略标记返回。</returns>
        public static string LimitLength(this string text, int length, string tag)
        {
            if (text.IsNullOrWhiteSpace() || text.Length <= length)
            {
                return text;
            }

            return text.Substring(0, length) + tag;
        }

        /// <summary>
        /// 隐藏字符串，必然显示最后一个字符。
        /// </summary>
        /// <param name="source"></param>
        /// <param name="tag">隐藏的符号。</param>
        /// <param name="number">符号个数。</param>
        /// <param name="startIndex">第几位开始隐藏。</param>
        /// <param name="hideNumber">隐藏的个数。（0：表示不使用）</param>
        /// <returns></returns>
        public static string GetHideString(this string source, string tag = "*", int number = 10, int startIndex = 1, int hideNumber = 0)
        {
            if (string.IsNullOrWhiteSpace(source))
                return source;

            if (startIndex < 0)
            {
                throw new ArgumentOutOfRangeException("startIndex");
            }

            if (startIndex >= source.Length)
            {
                return source;
            }

            var result = source.Substring(0, startIndex);

            if (number > 0)
            {
                for (int index = 0; index < number; index++)
                {
                    result += tag;
                }
            }

            if (hideNumber > 0)
            {
                if (source.Length > startIndex + hideNumber)
                {
                    result += source.Substring(startIndex + hideNumber);
                }
            }
            else
            {
                if (source.Length > 2)
                {
                    result += source.Substring(source.Length - 1, 1);
                }
            }

            return result;
        }
    }
}